package com.yc.sakuralxm.uestcscanning.adapters

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import com.alibaba.fastjson.serializer.AfterFilter

import java.util.ArrayList
import java.util.Arrays
import java.util.Collections
import java.util.Comparator
import java.util.Locale

/**
 * A concrete BaseAdapter that is backed by an array of arbitrary
 * objects.  By default this class expects that the provided resource id references
 * a single TextView.  If you want to use a more complex layout, use the constructors that
 * also takes a field id.  That field id should reference a TextView in the larger layout
 * resource.
 *
 *
 * However the TextView is referenced, it will be filled with the toString() of each object in
 * the array. You can add lists or arrays of custom objects. Override the toString() method
 * of your objects to determine what text will be displayed for the item in the list.
 *
 *
 * To use something other than TextViews for the array display, for instance, ImageViews,
 * or to have some of data besides toString() results fill the views,
 * override [.getView] to return the type of view you want.
 */
open class ArrayAdapter<T> : BaseAdapter, Filterable {
    /**
     * Contains the list of objects that represent the data of this ArrayAdapter.
     * The content of this list is referred to as "the array" in the documentation.
     */
    private var mObjects: MutableList<T>? = null

    /**
     * Lock used to modify the content of [.mObjects]. Any write operation
     * performed on the array should be synchronized on this lock. This lock is also
     * used by the filter (see [.getFilter] to make a synchronized copy of
     * the original array of data.
     */
    private val mLock = Any()

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter.
     */
    private var mResource: Int = 0

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter in a drop down widget.
     */
    private var mDropDownResource: Int = 0

    /**
     * If the inflated resource is not a TextView, [.mFieldId] is used to find
     * a TextView inside the inflated views hierarchy. This field must contain the
     * identifier that matches the one defined in the resource file.
     */
    private var mFieldId = 0

    /**
     * Indicates whether or not [.notifyDataSetChanged] must be called whenever
     * [.mObjects] is modified.
     */
    private var mNotifyOnChange = true

    /**
     * Returns the context associated with this array adapter. The context is used
     * to create views from the resource passed to the constructor.
     *
     * @return The Context associated with this adapter.
     */
    var context: Context? = null
        private set

    // A copy of the original mObjects array, initialized from and then used instead as soon as
    // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
    private var mOriginalValues: ArrayList<T>? = null
    private var mFilter: ArrayFilter? = null

    private var mInflater: LayoutInflater? = null
    protected var selection = -1


    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     * instantiating views.
     */
    constructor(context: Context, textViewResourceId: Int) {
        init(context, textViewResourceId, 0, ArrayList())
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     * instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     */
    constructor(context: Context, resource: Int, textViewResourceId: Int) {
        init(context, resource, textViewResourceId, ArrayList())
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     * instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    constructor(context: Context, textViewResourceId: Int, objects: Array<T>) {
        init(context, textViewResourceId, 0, Arrays.asList(*objects))
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     * instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    constructor(context: Context, resource: Int, textViewResourceId: Int, objects: Array<T>) {
        init(context, resource, textViewResourceId, Arrays.asList(*objects))
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a TextView to use when
     * instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    constructor(context: Context, resource: Int, objects: MutableList<T>) {
        init(context, resource, 0, objects)
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     * instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    constructor(context: Context, resource: Int, textViewResourceId: Int, objects: MutableList<T>) {
        init(context, resource, textViewResourceId, objects)
    }

    /**
     * Adds the specified object at the end of the array.
     *
     * @param object The object to add at the end of the array.
     */
    fun add(`object`: T) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                mOriginalValues!!.add(`object`)
            } else {
                mObjects!!.add(`object`)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    fun addIfNotHas(`object`: T) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                if (mOriginalValues!!.contains(`object`)) {
                    return
                }
                mOriginalValues!!.add(`object`)
            } else {
                if (mObjects!!.contains(`object`)) {
                    return
                }
                mObjects!!.add(`object`)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    fun addAllIfNotHas(collection: Collection<T>) {
        for (t in collection) {
            if (mOriginalValues != null) {
                if (!mOriginalValues!!.contains(t)) {
                    mOriginalValues!!.add(t)
                }
            } else {
                if (!mObjects!!.contains(t)) {
                    mObjects!!.add(t)
                }
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Adds the specified Collection at the end of the array.
     *
     * @param collection The Collection to add at the end of the array.
     */
    fun addAll(collection: Collection<T>) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                mOriginalValues!!.addAll(collection)
            } else {
                mObjects!!.addAll(collection)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Adds the specified items at the end of the array.
     *
     * @param items The items to add at the end of the array.
     */
    @SafeVarargs
    fun addAll(vararg items: T) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                Collections.addAll(mOriginalValues!!, *items)
            } else {
                Collections.addAll(mObjects!!, *items)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Inserts the specified object at the specified index in the array.
     *
     * @param object The object to insert into the array.
     * @param index The index at which the object must be inserted.
     */
    fun insert(`object`: T, index: Int) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                mOriginalValues!!.add(index, `object`)
            } else {
                mObjects!!.add(index, `object`)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Removes the specified object from the array.
     *
     * @param object The object to remove.
     */
    fun remove(`object`: T) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                mOriginalValues!!.remove(`object`)
            } else {
                mObjects!!.remove(`object`)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Remove all elements from the list.
     */
    fun clear() {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                mOriginalValues!!.clear()
            } else {
                mObjects!!.clear()
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * Sorts the content of this adapter using the specified comparator.
     *
     * @param comparator The comparator used to sort the objects contained
     * in this adapter.
     */
    fun sort(comparator: Comparator<in T>) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                Collections.sort(mOriginalValues!!, comparator)
            } else {
                Collections.sort(mObjects!!, comparator)
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * {@inheritDoc}
     */
    override fun notifyDataSetChanged() {
        super.notifyDataSetChanged()
        mNotifyOnChange = true
    }

    /**
     * Control whether methods that change the list ([.add],
     * [.insert], [.remove], [.clear]) automatically call
     * [.notifyDataSetChanged].  If set to false, caller must
     * manually call notifyDataSetChanged() to have the changes
     * reflected in the attached view.
     *
     * The default is true, and calling notifyDataSetChanged()
     * resets the flag to true.
     *
     * @param notifyOnChange if true, modifications to the list will
     * automatically call [                       ][.notifyDataSetChanged]
     */
    fun setNotifyOnChange(notifyOnChange: Boolean) {
        mNotifyOnChange = notifyOnChange
    }

    private fun init(context: Context, resource: Int, textViewResourceId: Int, objects: MutableList<T>) {
        this.context = context
        mInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        mDropDownResource = resource
        mResource = mDropDownResource
        mObjects = objects
        mFieldId = textViewResourceId
    }

    /**
     * {@inheritDoc}
     */
    override fun getCount(): Int {
        return mObjects!!.size
    }

    /**
     * {@inheritDoc}
     */
    override fun getItem(position: Int): T {
        return mObjects!![position]
    }

    /**
     * Returns the position of the specified item in the array.
     *
     * @param item The item to retrieve the position of.
     *
     * @return The position of the specified item.
     */
    fun getPosition(item: T): Int {
        return mObjects!!.indexOf(item)
    }

    /**
     * {@inheritDoc}
     */
    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    /**
     * {@inheritDoc}
     */
    override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
        return createViewFromResource(position, convertView, parent, mResource)
    }

    private fun createViewFromResource(position: Int, convertView: View?, parent: ViewGroup,
                                       resource: Int): View {
        val view: View
        val text: TextView

        if (convertView == null) {
            view = mInflater!!.inflate(resource, parent, false)
        } else {
            view = convertView
        }

        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = view as TextView
            } else if (mFieldId == -1) {
                if (mObjects != null && !mObjects!!.isEmpty()) {
                    loadViewData(view, position, getItem(position))
                }
                return view
            } else {
                //  Otherwise, find the TextView field within the layout
                text = view.findViewById(mFieldId) as TextView
            }
        } catch (e: ClassCastException) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView")
            throw IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e)
        }

        val item = getItem(position)

        // TODO  fleid  = 0
        //        if (item instanceof CharSequence) {
        //            text.setText((CharSequence)item);
        //        } else if(item instanceof IUIData){
        //            text.setText(((IUIData) item).getUIData());
        //        } else {
        //            text.setText(item.toString());
        //        }

        return view
    }

    /**
     * 加载数据
     */
    protected open fun loadViewData(view: View, position: Int, item: T) {

    }

    /**
     *
     * Sets the layout resource to create the drop down views.
     *
     * @param resource the layout resource defining the drop down views
     * @see .getDropDownView
     */
    fun setDropDownViewResource(resource: Int) {
        this.mDropDownResource = resource
    }

    /**
     * {@inheritDoc}
     */
    override fun getDropDownView(position: Int, convertView: View, parent: ViewGroup): View {
        return createViewFromResource(position, convertView, parent, mDropDownResource)
    }

    /**
     * {@inheritDoc}
     */
    override fun getFilter(): Filter {
        if (mFilter == null) {
            mFilter = ArrayFilter()
        }
        return mFilter as Filter
    }

    /**
     *
     * An array filter constrains the content of the array adapter with
     * a prefix. Each item that does not start with the supplied prefix
     * is removed from the list.
     */
    private inner class ArrayFilter : Filter() {
        override fun performFiltering(prefix: CharSequence?): Filter.FilterResults {
            val results = Filter.FilterResults()

            if (mOriginalValues == null) {
                synchronized(mLock) {
                    mOriginalValues = ArrayList(mObjects!!)
                }
            }

            if (prefix == null || prefix.length == 0) {
                var list: ArrayList<T>?=null
                synchronized(mLock) {
                    list = ArrayList(mOriginalValues!!)
                }
                results.values = list
                results.count = list!!.size
            } else {
                val prefixString = prefix.toString().toLowerCase(Locale.CHINA)

                var values: ArrayList<T>?=null
                synchronized(mLock) {
                    values = ArrayList(mOriginalValues!!)
                }

                val count = values!!.size
                val newValues = ArrayList<T>()

                for (i in 0 until count) {
                    val value = values!![i]
                    val valueText = value.toString().toLowerCase(Locale.CHINA)

                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString)) {
                        newValues.add(value)
                    } else {
                        val words = valueText.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                        val wordCount = words.size

                        // Start at index 0, in case valueText starts with space(s)

                        for (word in words) {
                            if (word.startsWith(prefixString)) {
                                newValues.add(value)
                                break
                            }
                        }
                    }
                }

                results.values = newValues
                results.count = newValues.size
            }

            return results
        }

        override fun publishResults(constraint: CharSequence, results: Filter.FilterResults) {
            //            mObjects = (List<T>) results.values;
            //            if (results.count > 0) {
            //                notifyDataSetChanged();
            //            } else {
            //                notifyDataSetInvalidated();
            //            }
        }
    }

    fun notifyDataSetChanged(`object`: T) {
        synchronized(mLock) {
            if (mOriginalValues != null) {
                if (mOriginalValues!!.contains(`object`)) {
                    val index = mOriginalValues!!.indexOf(`object`)
                    if (index > -1) {//包含就替换
                        mOriginalValues!!.removeAt(index)
                        mOriginalValues!!.add(index, `object`)
                    }
                }
            } else {
                if (mObjects!!.contains(`object`)) {
                    val index = mObjects!!.indexOf(`object`)
                    if (index > -1) {//包含就替换
                        mObjects!!.removeAt(index)
                        mObjects!!.add(index, `object`)
                    }
                }
            }
        }
        if (mNotifyOnChange) notifyDataSetChanged()
    }

    /**
     * 设置选中项
     */
//    fun setSelection(position: Int) {
//        selection = position
//        if (mNotifyOnChange) notifyDataSetChanged()
//    }

    companion object {

        /**
         * Creates a new ArrayAdapter from external resources. The content of the array is
         * obtained through [android.content.res.Resources.getTextArray].
         *
         * @param context The application's environment.
         * @param textArrayResId The identifier of the array to use as the data source.
         * @param textViewResId The identifier of the layout used to create views.
         *
         * @return An ArrayAdapter<CharSequence>.
        </CharSequence> */
        fun createFromResource(context: Context,
                               textArrayResId: Int, textViewResId: Int): ArrayAdapter<CharSequence> {
            val strings = context.resources.getTextArray(textArrayResId)
            return ArrayAdapter(context, textViewResId, strings)
        }
    }
}
